package game

import (
	"fmt"
	"strings"
	"time"

	"missevanbot/models"
	"missevanbot/modules"
	"missevanbot/utils"
)

type APMRace struct {
	*Game
	RandStr string
	Queue   []models.Player
}

const waitTime = 7

func NewAPMRace() *APMRace {
	return &APMRace{
		Game: &Game{Name: models.GameAPMRace},
	}
}

func (a *APMRace) Start(cmd *models.Command) {
	if cmd.Role > models.RoleAdmin {
		return
	}

	if a.State != models.StateReady {
		cmd.Output <- models.TplGameNotEnough
		return
	}

	cmd.Output <- models.TplAPMRaceStart

	go func() {
		time.Sleep(time.Duration(utils.RandomNumber(3, 15)) * time.Second) // Random interval.

		a.RandStr = utils.Itoa(utils.RandomNumber(10000, 99999))
		cmd.Output <- fmt.Sprintf(models.TplAPMRaceString, waitTime, a.RandStr)

		a.State = models.StateRunning      // state transfer
		time.Sleep(waitTime * time.Second) // Waiting for player new messages.

		// Game Over.
		text := strings.Builder{}
		df := a.diff()
		if len(df) != 0 {
			ns := make([]string, len(df))
			for k, v := range df {
				ns[k] = "@" + v.Name
			}
			text.WriteString(fmt.Sprintf(models.TplAPMRaceTimeout,
				strings.Join(ns, "，"),
				modules.Word(modules.WordPunish),
			))
		} else {
			text.WriteString(fmt.Sprintf(models.TplAPMRaceOver,
				a.Queue[len(a.Queue)-1].Name,
				modules.Word(modules.WordPunish),
			))
		}
		cmd.Output <- text.String()
		a.addScore(cmd.ID)
		stop(cmd)
	}()
}

func (a *APMRace) Action(cmd *models.Command, textMsg models.FmTextMessage) {
	if a.State != models.StateRunning {
		return
	}

	user := cmd.User
	if !a.isPlayer(user.UserID) {
		return
	}

	// Check input.
	if textMsg.Message != a.RandStr {
		cmd.Output <- fmt.Sprintf(models.TplGameInputIllegal, user.Username)
		return
	}

	a.Queue = append(a.Queue, models.Player{
		ID:   user.UserID,
		Name: user.Username,
	})
}

func (a *APMRace) diff() []models.Player {
	ll := make([]models.Player, 0, len(a.Players)-len(a.Queue))

	for _, p := range a.Players {
		if !a.inQueue(p.ID) {
			ll = append(ll, p)
		}
	}
	return ll
}

func (a *APMRace) inQueue(uid int64) bool {
	for _, v := range a.Queue {
		if v.ID == uid {
			return true
		}
	}
	return false
}

func (a *APMRace) addScore(rid int64) {
	base := models.ScoreAPMRace

	for i := len(a.Queue) - 1; i >= 0; i-- {
		addScore(rid, []models.Player{a.Queue[i]}, base*(len(a.Queue)-i))
	}
}
